package com.qlogic.commons.platform.impls.lucene.indexer;

import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;

import com.qlogic.commons.StandardLogger;
import com.qlogic.commons.exceptions.BaseException;
import com.qlogic.commons.kernel.Kernel;
import com.qlogic.commons.platform.Executable;
import com.qlogic.commons.platform.ExecutableException;
import com.qlogic.commons.platform.ServiceExecutionException;
import com.qlogic.commons.platform.impls.lucene.model.DocumentWrapper;
import com.qlogic.commons.platform.impls.lucene.model.RegistryRegion;

public class ContentManagerExecutable extends StandardLogger implements Executable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -7563295939296313227L;
	
	private static final String REGISTRY_PATH = "contentService/registry";
	private static final String INDEXERS_PATH = "contentService/indexers/";

	public void execute () throws ExecutableException {
		console (" ----> [Start]");
		ContentRegistry contentRegistry;
		try {
			contentRegistry = getContentRegistry ();
		} catch (ServiceExecutionException e) {
			throw new ExecutableException (e);
		}
		Iterator regions;
		try {
			regions = contentRegistry.getRegionNames ();
		} catch (BaseException e) {
			throw new ExecutableException (e);
		}
		while (regions.hasNext ()) {
			String regionName = (String)regions.next ();
			console (" ----> [Process Region] " + regionName);
			RegistryRegion region;
			try {
				region = contentRegistry.getRegion (regionName);
			} catch (BaseException e) {
				throw new ExecutableException (e);
			}
			console (" ----> [Process Region] " + region);
			if (region == null) {
				continue;
			}
			Vector documents = region.getDocuments ();
			if (documents == null || documents.isEmpty ()) {
				continue;
			}

			IndexWriter indexWriter = null;
			IndexReader indexReader = null;
			
			Directory directory = null;
			try {
				directory = (Directory)Kernel.getResource (INDEXERS_PATH + region.getIndexer() + "/directory").getValue ();
			} catch (BaseException ex) {
				throw new ExecutableException (ex);
			} 
			
			try {
				if (IndexReader.isLocked (directory)) {
					IndexReader.unlock (directory);
				}
			} catch (IOException ioex) {
				throw new ExecutableException (ioex);
			} 
			
			if (region.getAction () == ContentRegistry.ADD) {
				try {
					indexWriter = (IndexWriter)Kernel.getResource (INDEXERS_PATH + region.getIndexer()).getValue ();
				} catch (BaseException e) {
					e.printStackTrace();
					throw new ExecutableException (e);
				} 
			} else if (region.getAction () == ContentRegistry.DELETE) {
				try {
					indexReader = 
						IndexReader.open (directory);
				} catch (IOException ioex) {
					ioex.printStackTrace();
					throw new ExecutableException (ioex);
				}
			}
			
			synchronized (documents) {
				int count = documents.size ();
				console ("\t ----> [ADDS,DELETES,UPDATES COUNT] " + count);
				for (int i = count - 1; i >= 0; i--) {
					DocumentWrapper documentWrapper = null;
					try {
						documentWrapper = (DocumentWrapper)documents.elementAt (i);
						if (documentWrapper.getDependsOn () == null) {
							if (region.getAction () == ContentRegistry.ADD) {
								try {
									indexWriter.addDocument (LuceneUtils.toDocument (documentWrapper));
									console ("\t ----> Document [" + 
											documentWrapper.getId () + "] Added to Index" );
								} catch (IOException ioex) {
									throw new ServiceExecutionException (ioex);
								} 
							} else if (region.getAction () == ContentRegistry.DELETE) {
								if (documentWrapper.getId () != null) {
									LuceneUtils.delete (documentWrapper.getId (), region.getIndexer (), 
											indexWriter, indexReader);
									console ("\t ----> Document [" + 
											documentWrapper.getId () + "] Deleted from Index" );
								} else {
									LuceneUtils.delete (documentWrapper.getFieldName (), documentWrapper.getFieldValue (),
											region.getIndexer (), indexWriter, indexReader);
									console ("\t ----> Document [ (" + 
											documentWrapper.getFieldName () + ") = (" + documentWrapper.getFieldValue () + ")] Deleted from Index" );
								}
								
							}
							contentRegistry.unregister (region, documentWrapper);
						}
					} catch (BaseException e) {
						console ("\t ----> Error occured when '" + 
								((region.getAction () == ContentRegistry.ADD) ? "Adding" : "Deleting") + 
								"' [" + 
								( (documentWrapper.getId () != null) ? String.valueOf (documentWrapper.getId ()) : ("(" + 
										documentWrapper.getFieldName () + ") = (" + documentWrapper.getFieldValue () + ")"))
								+ "] to/from Index", ERROR);
						console ("==============================================", ERROR);
						console (e.getCauseText (), ERROR);
						console ("==============================================", ERROR);
						continue;
					}
					if (indexWriter != null && (i % 10 == 0)) {
						try {
							indexWriter.optimize ();
						} catch (IOException ioex) {
							ioex.printStackTrace ();
						}
					}
				}
			}
			if (indexWriter != null) {
				try {
					indexWriter.optimize ();
					indexWriter.close();
				} catch (IOException ioex) {
					ioex.printStackTrace ();
				}
			}
			if (indexReader != null) {
				try {
					indexReader.close();
				} catch (IOException ioex) {
					ioex.printStackTrace ();
				}
			}
		}
		try {
			contentRegistry.flush ();
		} catch (BaseException e) {
			e.printStackTrace();
		}
		
	}
	
	protected static ContentRegistry getContentRegistry () throws ServiceExecutionException {
		try {
			return (ContentRegistry)Kernel.getResource (REGISTRY_PATH).getValue ();
		} catch (BaseException e) {
			throw new ServiceExecutionException (e);
		} 
	}

	public String getLoggerName() {
		return "Content Manager Scheduler";
	}

	public void setLoggerName(String arg0) {
	}
	
}
